From c238be5234e933abecc6c5918ade7e9bf8e7cacf Mon Sep 17 00:00:00 2001 From: oliskoli Date: Fri, 13 Apr 2007 08:05:23 +0000 Subject: [PATCH] Add code for a common string-to-coordinates parser. --- Makefile.in | 5 ++- defs.h | 16 +++++++ garmin_tables.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++ garmin_tables.h | 5 +++ util.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 253 insertions(+), 2 deletions(-) diff --git a/Makefile.in b/Makefile.in index 60f5766ef..d08bcf527 100644 --- a/Makefile.in +++ b/Makefile.in @@ -411,7 +411,8 @@ garmin_fs.o: garmin_fs.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ jeeps/gpsmath.h jeeps/gpsmem.h jeeps/gpsrqst.h jeeps/gpsinput.h \ jeeps/gpsproj.h garmin_tables.h garmin_tables.o: garmin_tables.c garmin_tables.h defs.h config.h queue.h \ - gbtypes.h zlib/zlib.h zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h + gbtypes.h zlib/zlib.h zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h \ + jeeps/gpsmath.h garmin_txt.o: garmin_txt.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h csv_util.h garmin_fs.h \ jeeps/gps.h jeeps/../defs.h jeeps/gpsport.h jeeps/gpsdevice.h \ @@ -655,7 +656,7 @@ units.o: units.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h util_crc.o: util_crc.c util.o: util.c defs.h config.h queue.h gbtypes.h zlib/zlib.h zlib/zconf.h \ - gbfile.h cet.h cet_util.h inifile.h + gbfile.h cet.h cet_util.h inifile.h jeeps/gpsmath.h uuid.o: uuid.c uuid.h vcf.o: vcf.c defs.h config.h queue.h gbtypes.h zlib/zlib.h zlib/zconf.h \ gbfile.h cet.h cet_util.h inifile.h jeeps/gpsmath.h jeeps/gps.h \ diff --git a/defs.h b/defs.h index 0eb901d9e..5117a1183 100644 --- a/defs.h +++ b/defs.h @@ -850,6 +850,22 @@ void le_write_double(void *p, double d); double ddmm2degrees(double ddmm_val); double degrees2ddmm(double deg_val); +typedef enum { + grid_unknown = -1, + grid_lat_lon_ddd = 0, + grid_lat_lon_dmm = 1, + grid_lat_lon_dms = 2, + grid_bng = 3, + grid_utm = 4 +} grid_type; + +#define GRID_INDEX_MIN grid_lat_lon_ddd +#define GRID_INDEX_MAX grid_utm +#define DATUM_WGS84 118 + +int parse_coordinates(const char *str, int datum, const grid_type grid, + double *latitude, double *longitude, const char *module); + /* * From util_crc.c */ diff --git a/garmin_tables.c b/garmin_tables.c index a82369967..47feca023 100644 --- a/garmin_tables.c +++ b/garmin_tables.c @@ -21,6 +21,8 @@ */ #include "garmin_tables.h" +#include "jeeps/gpsmath.h" + #include #include @@ -597,6 +599,49 @@ char *gt_display_mode_names[] = { "Symbol & Description" }; +typedef struct { + char *shortname; + char *longname; + grid_type grid; +} grid_mapping_t; + +/* gt_mps_grid_names: !!! degree sign substituted with '*' !!! */ + +grid_mapping_t gt_mps_grid_names[] = +{ + { "ddd", "Lat/Lon hddd.ddddd*", grid_lat_lon_ddd }, + { "dmm", "Lat/Lon hddd*mm.mmm'", grid_lat_lon_dmm }, + { "dms", "Lat/Lon hddd*mm'ss.s\"", grid_lat_lon_dms }, + { "bng", "British National Grid", grid_bng }, + { "utm", "UTM", grid_utm }, + { NULL, NULL, 0 } +}; + +/* gt_mps_datum_names: */ + +typedef struct { + char *jeeps_name; + char *mps_name; +} datum_mapping_t; + +/* will be continued (when requested) */ +datum_mapping_t gt_mps_datum_names[] = +{ + { "Alaska-NAD27", "NAD27 Alaska" }, + { "Bahamas NAD27", "NAD27 Bahamas" }, + { "Canada_Mean(NAD27)", "NAD27 Canada" }, + { "Canal_Zone_(NAD27)", "NAD27 Canal Zone" }, + { "Carribean NAD27", "NAD27 Caribbean" }, + { "Cent America NAD27", "NAD27 Central" }, + { "Cuba NAD27", "NAD27 Cuba" }, + { "Geodetic Datum 49", "Geodetic Datum '49" }, + { "Greenland NAD27", "NAD27 Greenland" }, + { "Mexico NAD27", "NAD27 Mexico" }, + { "North America 83", "NAD83" }, + { "OSGB36", "Ord Srvy Grt Britn" }, + { NULL, NULL } +}; + unsigned char gt_switch_display_mode_value(const unsigned char display_mode, const int protoid, const char device) { @@ -834,6 +879,77 @@ gt_get_icao_cc(const char *country, const char *shortname) return NULL; } +grid_type +gt_lookup_grid_type(const char *grid_name, const char *module) +{ + grid_mapping_t *g; + + for (g = gt_mps_grid_names; (g->shortname); g++) { + if ((case_ignore_strcmp(grid_name, g->shortname) == 0) || + (case_ignore_strcmp(grid_name, g->longname) == 0)) + return g->grid; + } + + fatal("%s: Unsupported grid (%s)! See GPSBabel help for supported grids.\n", + module, grid_name); + + return grid_unknown; /* (warnings) */ +} + +char * +gt_get_mps_grid_longname(const grid_type grid, const char *module) +{ + if ((grid < GRID_INDEX_MIN) || (grid > GRID_INDEX_MAX)) + fatal("%s: Grid index out of range %d (%d..%d)!", + module, (int) grid, + (int)GRID_INDEX_MIN, (int)GRID_INDEX_MAX); + return gt_mps_grid_names[grid].longname; +} + +char * +gt_get_mps_datum_name(const int datum_index) +{ + char *result; + datum_mapping_t *d; + + result = GPS_Math_Get_Datum_Name(datum_index); + + for (d = gt_mps_datum_names; (d->jeeps_name); d++) + if (case_ignore_strcmp(result, d->jeeps_name) == 0) return d->mps_name; + + return result; +} + +int +gt_lookup_datum_index(const char *datum_str, const char *module) +{ + datum_mapping_t *d; + int result; + const char *name = datum_str; + + for (d = gt_mps_datum_names; (d->jeeps_name); d++) { + if (case_ignore_strcmp(name, d->mps_name) == 0) { + name = d->jeeps_name; + break; + } + } + + result = GPS_Lookup_Datum_Index(name); + + if (result < 0) { + char *tmp; + xasprintf(&tmp, "%s mean", datum_str); + result = GPS_Lookup_Datum_Index(tmp); + xfree(tmp); + } + + is_fatal(result < 0, + "%s: Unsupported datum (%s)! See GPSBabel help for supported datums.", + module, datum_str); + + return result; +} + #if MAKE_TABLE /* diff --git a/garmin_tables.h b/garmin_tables.h index 79667843c..c846c94c5 100644 --- a/garmin_tables.h +++ b/garmin_tables.h @@ -92,4 +92,9 @@ unsigned char gt_convert_category(const char *name, int *category); unsigned char gt_switch_display_mode_value(const unsigned char display_mode, const int protoid, const char device); +grid_type gt_lookup_grid_type(const char *grid_name, const char *module); +char *gt_get_mps_grid_longname(const grid_type grid, const char *module); +int gt_lookup_datum_index(const char *datum_str, const char *module); +char *gt_get_mps_datum_name(const int datum_index); + #endif diff --git a/util.c b/util.c index 1af7d25e6..617199e7d 100644 --- a/util.c +++ b/util.c @@ -20,6 +20,8 @@ */ #include "defs.h" +#include "jeeps/gpsmath.h" + #include #include #include @@ -992,6 +994,117 @@ double degrees2ddmm(double deg_val) { return (double) (deg * 100.0) + ((deg_val - deg) * 60.0); } +/* + * Convert string 'str' into geodetic latitide & longitude values. The format + * will be interpreted depending on 'grid' parameter. + * + * return value: number of characters efective parsed + */ + +int +parse_coordinates(const char *str, int datum, const grid_type grid, + double *latitude, double *longitude, const char *module) +{ + double lat, lon; + unsigned char lathemi, lonhemi; + int deg_lat, deg_lon, min_lat, min_lon; + char map[3]; + int utmz, utme, utmn; + char utmc; + int valid, result, ct; + double lx, ly; + const char *format; + + valid = 1; + + switch(grid) { + + case grid_lat_lon_ddd: + format = "%c%lf %c%lf%n"; + ct = sscanf(str, format, + &lathemi, &lat, &lonhemi, &lon, &result); + valid = (ct == 4); + break; + + case grid_lat_lon_dmm: + format = "%c%d %lf %c%d %lf%n"; + ct = sscanf(str, format, + &lathemi, °_lat, &lat, &lonhemi, °_lon, &lon, &result); + valid = (ct == 6); + if (valid) { + lat = (double)deg_lat + (lat / (double)60); + lon = (double)deg_lon + (lon / (double)60); + } + break; + + case grid_lat_lon_dms: + format = "%c%d %d %lf %c%d %d %lf%n"; + ct = sscanf(str, format, + &lathemi, °_lat, &min_lat, &lat, &lonhemi, °_lon, &min_lon, &lon, + &result); + valid = (ct == 8); + if (valid) { + lat = (double)deg_lat + ((double)min_lat / (double)60) + (lat / (double)3600.0); + lon = (double)deg_lon + ((double)min_lon / (double)60) + (lon / (double)3600.0); + } + break; + + case grid_bng: + format = "%2s %lf %lf%n"; + ct = sscanf(str, format, + map, &lx, &ly, + &result); + valid = (ct == 3); + if (valid) { + if (! GPS_Math_UKOSMap_To_WGS84_M(map, lx, ly, &lat, &lon)) + fatal("%s: Unable to convert BNG coordinates (%s)!\n", + module, str); + } + datum = DATUM_WGS84; /* fix */ + lathemi = lonhemi = '\0'; + break; + + case grid_utm: + format = "%d %c %d %d%n"; + ct = sscanf(str, format, + &utmz, &utmc, &utme, &utmn, + &result); + valid = (ct == 4); + if (valid) { + valid = GPS_Math_UTM_EN_To_Known_Datum(&lat, &lon, utme, utmn, utmz, utmc, datum); + if (! valid) + fatal("%s: Unable to convert UTM coordinates (%s)!\n", + module, str); + } + lathemi = lonhemi = '\0'; + break; + + default: + /* this should never happen in a release version */ + fatal("%s/util: Unknown grid in parse_coordinates (%d)!\n", + module, (int)grid); + } + + if (!valid) { + warning("%s: sscanf error using format \"%s\"\n", module, format); + fatal( "%s: could not convert data \"%s\"!\n", module, str); + } + + if (lathemi == 'S') lat = -lat; + if (lonhemi == 'W') lon = -lon; + + if (datum != DATUM_WGS84) { + double alt; + GPS_Math_Known_Datum_To_WGS84_M(lat, lon, (double) 0.0, + &lat, &lon, &alt, datum); + } + + if (latitude) *latitude = lat; + if (longitude) *longitude = lon; + + return result; +} + /* * replace a single occurrence of "search" in "s" with "replace". * Returns an allocated copy if substitution was made, otherwise returns NULL. -- 2.30.2